#include "connection_socket.h"



	connection_socket::connection_socket(){
		this->sockfd = 0;
		this->sock_cli = 0;
		this->port = 5555;
		this->debug_mode = false;
		this->taille_buffer = SIZE_DATA*2;
	}

	connection_socket::~connection_socket(){
		if(sockfd!=0)
			this->close_socket();
	}

	bool connection_socket::connect_socket(char* addr_ip){
        this->addr_ip = addr_ip;
        int result = 0;
		this->requete = new requete_socket();
		this->reponse = new requete_socket();
		this->sockfd = socket(PF_INET,SOCK_STREAM, 0);
		if(this->sockfd == INVALID_SOCKET){
			this->print("Problème lors de la création du socket : socket()");
			return false;
		}
		this->print("Socket : OK");
		struct hostent *hp;
        hp = gethostbyname(this->addr_ip);
        memcpy(&addr.sin_addr.s_addr, hp->h_addr, hp->h_length);
		this->addr.sin_family = PF_INET;
		this->addr.sin_port = htons(port);
        result = connect(this->sockfd, (struct sockaddr *)&(this->addr), (socklen_t)sizeof(this->addr));
        if(this->sockfd == INVALID_SOCKET){
			this->print("Problème lors de la connexion : connect()");
			return false;
		}
		this->print("Connexion : OK");
	}

	bool connection_socket::connect_socket(){
		int result = 0;
		this->requete = new requete_socket();
		this->reponse = new requete_socket();
		this->sockfd = socket(PF_INET,SOCK_STREAM, 0);
		if(this->sockfd == INVALID_SOCKET){
			this->print("Problème lors de la création du socket : socket()");
			return false;
		}
		this->print("Socket : OK");
		this->addr.sin_family = PF_INET;
		this->addr.sin_addr.s_addr = INADDR_ANY;
		this->addr.sin_port = htons(port);
		result = bind(this->sockfd, (struct sockaddr *)&(this->addr), (socklen_t)sizeof(this->addr));
		if(result == INVALID_SOCKET){
			this->print("Problème lors du bind");
			return false;
		}
		this->print("Bind: OK");
		result = listen(this->sockfd, 1000);
		if(result == INVALID_SOCKET){
			this->print("Problème lors du listen");
			return false;
		}
		this->print("listen: OK");
		return true;
	}

	bool connection_socket::accept_socket(){
        int length = sizeof(this->addr);
        this->sock_cli = accept(this->sockfd, (struct sockaddr *)&(this->addr),(socklen_t *)&length);
        if(this->sock_cli == INVALID_SOCKET){
            this->print("Problème lors de la réception : accept()");
            return false;
        }
        this->print("accept: OK");
        return true;
	}

	requete_socket* connection_socket::recv_socket(){
        int result;
        if(this->sock_cli==0){
            char tmp[SIZE_STRING] = "";
            result = recv(this->sockfd, tmp, sizeof(tmp),0);
            this->requete->type = atoi(tmp);
            result = recv(this->sockfd, this->requete->login, sizeof(this->requete->login),0);
            result = recv(this->sockfd, this->requete->pass, sizeof(this->requete->pass),0);
            result = recv(this->sockfd, this->requete->dest, sizeof(this->requete->dest),0);
            result = recv(this->sockfd, this->requete->data, sizeof(this->requete->data),0);
            result = recv(this->sockfd, this->requete->checksum, sizeof(this->requete->checksum),0);
            result = recv(this->sockfd, tmp, sizeof(tmp),0);
            this->requete->size = atoi(tmp);
        }
        else{
            char tmp[SIZE_STRING] = "";
            result = recv(this->sock_cli, tmp, sizeof(tmp),0);
            this->requete->type = atoi(tmp);
            result = recv(this->sock_cli, this->requete->login, sizeof(this->requete->login),0);
            result = recv(this->sock_cli, this->requete->pass, sizeof(this->requete->pass),0);
            result = recv(this->sock_cli, this->requete->dest, sizeof(this->requete->dest),0);
            result = recv(this->sock_cli, this->requete->data, sizeof(this->requete->data),0);
            result = recv(this->sock_cli, this->requete->checksum, sizeof(this->requete->checksum),0);
            result = recv(this->sock_cli, tmp, sizeof(tmp),0);
            this->requete->size = atoi(tmp);
        }
        if(result == INVALID_SOCKET){
            this->print("Problème lors du read : recv()");
            this->requete->type = SOCKET_ERROR;
            return this->requete;
        }
        this->print("read: OK");
        return this->requete;

	}

	bool connection_socket::close_socket_cli(){
        close(this->sock_cli);
        this->sock_cli = 0;
        return true;
	}

	bool connection_socket::send_socket(requete_socket* message){
        this->reponse = message;
        strcpy(this->reponse->checksum, md5(this->reponse->data));
        int result;
        if(this->sock_cli==0){
            char tmp[SIZE_STRING] = "";
            sprintf(tmp,"%d",this->reponse->type);
            result = send(this->sockfd, tmp, sizeof(tmp), 0);
            result = send(this->sockfd, this->reponse->login, sizeof(this->reponse->login), 0);
            result = send(this->sockfd, this->reponse->pass, sizeof(this->reponse->pass), 0);
            result = send(this->sockfd, this->reponse->dest, sizeof(this->reponse->dest), 0);
            result = send(this->sockfd, this->reponse->data, sizeof(this->reponse->data), 0);
            result = send(this->sockfd, this->reponse->checksum, sizeof(this->reponse->checksum), 0);
            sprintf(tmp,"%d",this->reponse->size);
            result = send(this->sockfd, tmp, sizeof(tmp), 0);
        }
        else{
            char tmp[SIZE_STRING] = "";
            sprintf(tmp,"%d",this->reponse->type);
            result = send(this->sock_cli, tmp, sizeof(tmp), 0);
            result = send(this->sock_cli, this->reponse->login, sizeof(this->reponse->login), 0);
            result = send(this->sock_cli, this->reponse->pass, sizeof(this->reponse->pass), 0);
            result = send(this->sock_cli, this->reponse->dest, sizeof(this->reponse->dest), 0);
            result = send(this->sock_cli, this->reponse->data, sizeof(this->reponse->data), 0);
            result = send(this->sock_cli, this->reponse->checksum, sizeof(this->reponse->checksum), 0);
            printf(tmp,"%d",this->reponse->size);
            result = send(this->sock_cli, tmp, sizeof(tmp), 0);
        }
        if(result == INVALID_SOCKET){
            this->print("Problème lors du write : send()");
            return false;
        }
        this->print("write: OK");
		return true;
	}
	bool connection_socket::close_socket(){
        if(this->sock_cli!=0){
            close(this->sock_cli);
        }
		close(this->sockfd);
		return true;
	}

	void connection_socket::print(char *message){
		if(this->debug_mode)
			printf("%s\n", message);
	}

	bool connection_socket::send_file(char* path, char* name_file, requete_socket* message){
	    //printf("%s\n",path);
	    int fd = open(path, O_RDONLY);
	    if(fd<0){
            this->print("Lecture du fichier KO");
            return false;
	    }
	    this->print("Lecture du fichier OK");
	    message->type = SOCKET_NAME_FILE;
	    strcpy(message->data, name_file);
	    this->send_socket(message);
        char buffer[SIZE_DATA] = "";
        int size_of_file = 0;
        requete_socket* paquet = new requete_socket;
        while(int size = read(fd, paquet->data, SIZE_DATA)){
            paquet->type = SOCKET_FILE;
            paquet->size = size;
            size_of_file += size;
            //printf("Size : %d - %d\n",paquet->size, strlen(paquet->data));
            this->send_socket(paquet);
            paquet = new requete_socket;
        }
        requete_socket* verif = new requete_socket();
        verif->type = SOCKET_END_OF_FILE;
        sprintf(verif->data,"%d",size_of_file);
        verif->size = size_of_file;
        //printf("%d\n",size_of_file);
        this->send_socket(verif);
        close(fd);
        return true;
	}

	bool connection_socket::recv_file(){
        requete_socket* message = this->recv_socket();
        if(message->type != SOCKET_NAME_FILE){
            this->print(message->data);
            //printf("%d - %s\n",message->type, message->data);
            this->print("Mauvaise socket reçu !");
            return false;
        }
        char path[SIZE_DATA];
        strcpy(path, message->data);
        int fd = open(message->data, O_RDWR | O_CREAT);
        requete_socket* paquet;
        requete_socket* last_paquet;
        int size_of_file = 0;
        do{
            paquet = this->recv_socket();

            if(paquet->type==SOCKET_FILE){
                //printf("Size : %d - %d\n",paquet->size, strlen(paquet->data));
                write(fd, paquet->data, paquet->size);
                size_of_file += paquet->size;

                last_paquet = new requete_socket;
                for(int i=0;i<SIZE_DATA; i++)
                    last_paquet->data[i] = paquet->data[i];
            }
        }
        while(paquet->size==SIZE_DATA);
        requete_socket* verif = this->recv_socket();
        if(verif->type==SOCKET_END_OF_FILE){
            verif->size = atoi(verif->data);
            //printf("%d || %d\n",verif->size, size_of_file);
            if(verif->size!=size_of_file){
                write(fd, last_paquet->data, verif->size-size_of_file);
            }
        }
        close(fd);
        chmod(path,777);
        return true;
	}
